﻿#include <iostream>
#include <cassert>
#include <cstddef>

int main()
{
	std::cout << "Hello World!\n";

	//要动态分配单个变量，我们使用new运算符
	int* p{ new int };
	*p = 12;
	std::cout << *p << "\n";

	//销毁单个变量
	// 假设 ptr 之前是通过new分配出来的
	delete p; // 将ptr指向的地址归还给操作系统
	p = nullptr; // ptr赋值为nullptr

	//指向已释放内存的指针称为悬空指针。解引用或删除悬空指针将导致未定义的行为。

	//默认情况下，如果new失败，则抛出bad_alloc异常。
	int* value{ new (std::nothrow) int{} }; // 请求分配内存
	if (!value) // 处理返回为空的情况
	{
		// 做错误处理
		std::cerr << "Could not allocate memory\n";
	}


	//删除空指针没有任何问题
	//如果ptr不为nullptr，则将删除动态分配的内存。如果为nullptr，则不会发生任何事情。
	delete p; //目前p已经是空指针

	//动态分配的内存将保持分配状态，直到它被显式释放或程序结束
	/*
	当程序在将动态分配的内存返回给操作系统之前丢失其地址时，
	就会发生内存泄漏。发生这种情况时，程序无法删除动态分配的内存，
	因为它不再知道它在哪里。操作系统也无法使用该内存，因为该内存被认为仍在由程序使用。
	*/

	int length = 30;
	int* array{ new int[length] {} }; // 使用 数组 new.  注意这里长度不再需要是常量了!
	array[0] = 5; // 将第 0 个元素设置为 5
	delete[] array; // 使用 数组 delete 进行回收


	// C++11开始，初始化动态分配的数组
	int* array2{ new int[5] { 9, 7, 5, 3, 1 } };
	// 使用auto，可以避免写两遍类型名
	auto* array3{ new int[5] { 9, 7, 5, 3, 1 } };



	//在创建对象时调用构造函数，在销毁对象时调用析构函数。

	//RAII（Resource Acquisition Is Initialization，资源获取即初始化）
	// 是一种编程技术，其中资源使用与具有自动持续时间的对象（例如，
	// 非动态分配的对象）的生命周期相关联。在C++中，RAII是通过具有
	// 构造函数和析构函数的类来实现的。如下面的IntArray类


	int* pp{ new int };
	*pp = 12;
	//指向指针的指针
	int** pt = &pp; //p本身就是一个指针
	std::cout << **pt << '\n'; // 解引用两次，获取int值

	//动态分配二维数组
	//int x{ 7 }; // non-constant
	//int (*array)[5] { new int[x][5] }; // 最右边的数组一定得是constexpr


	//void指针，也称为泛型指针，是一种特殊类型的指针，可以指向任何
	// 数据类型的对象！使用void关键字作为指针的类型，
	void* ptr = pp;

	//由于void指针不知道它所指向的对象类型，因此解引用void指针是非法的。
	// 相反，在执行解引用之前，必须首先将void指针转换为其它指针类型。
	//std::cout << *ptr << '\n'; //错误，编译不通过
	std::cout << *static_cast<int*>(ptr) << '\n'; //将void指针转换为目标指针后在解引用


	/*
	由于void指针不知道它所指向的对象类型，因此delete void指针将导致未定义的行为。
	如果需要删除void指针，请首先将其static_cast转换回适当的类型。

	不能对空指针进行指针运算。这是因为指针算法要求指针知道它所指向的对象的大小，
	因此它可以适当地增加或减小指针。

	请注意，没有所谓的void引用。这是因为void引用的类型为void& ，
	完全不知道它引用的值的类型。
	*/
	delete ptr; //这里可以执行


	return EXIT_SUCCESS;
}



class IntArray
{
private:
	int* m_array{};
	int m_length{};

public:
	IntArray(int length) // 构造函数
	{
		assert(length > 0);

		m_array = new int[static_cast<std::size_t>(length)] {};
		m_length = length;
	}

	~IntArray() // 析构函数
	{
		// 删除初始化时动态分配的数组
		delete[] m_array;
	}

	void setValue(int index, int value) { m_array[index] = value; }
	int getValue(int index) { return m_array[index]; }

	int getLength() { return m_length; }
};
